/*******************************************************************
 File:     history.c
 Purpose:  Providing history support for things
 Author:   Justin Fletcher
 Date:     12 Jan 1997
 ******************************************************************/

#include "history.h"
#include "string.h"
#include "memory.h"
#include "fileio.h"
#define NULL 0

typedef struct hist_item {
  char *line;
  struct hist_item *next;
  struct hist_item *prev;
} hist_item;

typedef struct history {
  int maxlen; /* maximum number of lines (0 = infinite) */
  int sofar;  /* number of lines so far */
  hist_item *last;
  hist_item *first;
} history;

/*********************************************** <c> Gerph *********
 Function:     history_create
 Description:  Create a history block
 Parameters:   maxlen = maximum length of the history, or 0 for
                        infinite
 Returns:      history handle, or NULL if could not create
 ******************************************************************/
void *history_create(int maxlen)
{
  history *hist=malloc(sizeof(history));

  if (hist!=NULL) {
    hist->maxlen=maxlen;
    hist->sofar=0; /* no lines yet */
    hist->last=NULL;
    hist->first=NULL;
  }
  return hist;
}

/*********************************************** <c> Gerph *********
 Function:     history_destory
 Description:  Destory a history block
 Parameters:   histv = history handle
 Returns:      none
 ******************************************************************/
void history_destroy(void *histv)
{
  history *hist=(history *)histv;

  hist_item *item=hist->last;
  while (item!=NULL) {
    hist_item *next=item->next;
    free(item->line);
    free(item);
    item=next;
  }
  free(hist);
}

/*********************************************** <c> Gerph *********
 Function:     history_add
 Description:  Add a line to the buffer
 Parameters:   histv = history handle
               line = line to store
 Returns:      none
 ******************************************************************/
void history_add(void *histv,char *line)
{
  history *hist=(history *)histv;
  hist_item *item=malloc(sizeof(hist_item));
  char *linec;

  if (item==NULL)
    return; /* we couldn't create a block */

  if (line==NULL)
    line=""; /* they passed a null pointer ! */

  item->next=hist->last;
  item->prev=NULL;
  linec=malloc(strlen(line)+1);
  if (linec==NULL)
    free(item);
  else {
    item->line=strcpy(linec,line);
    hist->last=item;
    if (item->next == NULL)
      hist->first=item;
    else
      item->next->prev=item;
  }
  hist->sofar++;
  if ( (hist->sofar > hist->maxlen) &&
       (hist->maxlen != 0) ) {
    item=hist->first;
    hist->first=hist->first->prev;
    hist->first->next=NULL;
    free(item->line);
    free(item);
  }
}

/*********************************************** <c> Gerph *********
 Function:     history_previous
 Description:  returns the string previously added to the buffer
 Parameters:   histv = history handle
               last = last line returned, or NULL to start
 Returns:      pointer to line, or NULL if none
 ******************************************************************/
char *history_previous(void *histv,char *last)
{
  history *hist=(history *)histv;
  hist_item *item;

  if (last==NULL)
    return hist->last->line;

  item=hist->last;
  while ( (item!=NULL) && (item->line != last) )
    item=item->next;
  if (item!=NULL) item=item->next;
  if (item==NULL)
    return NULL;
  else
    return item->line;
}

/*********************************************** <c> Gerph *********
 Function:     history_next
 Description:  returns the string subsequently added to the buffer
 Parameters:   histv = history handle
               last = last line returned, or NULL to start
 Returns:      pointer to line, or NULL if none
 ******************************************************************/
char *history_next(void *histv,char *last)
{
  history *hist=(history *)histv;
  hist_item *item;

  if (last==NULL)
    return hist->first->line;

  item=hist->first;
  while ( (item!=NULL) && (item->line != last) )
    item=item->prev;
  if (item!=NULL) item=item->prev;
  if (item==NULL)
    return NULL;
  else
    return item->line;
}

/* void temp(void) */
/* { */
  /* char *justin; */
  /* justin=gets(justin); */
/* } */
